/**********************************************************************
 *                                                                    *
 * tgt - Tiny Graphics Toolbox                                        *
 *                                                                    *
 * Copyright (C) 2006-2008 Visualization and Computer Graphics Group, *
 * Department of Computer Science, University of Muenster, Germany.   *
 * <http://viscg.uni-muenster.de>                                     *
 *                                                                    *
 * This file is part of the tgt library. This library is free         *
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
 * GNU Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

#ifndef TGT_QUADRICS_H
#define TGT_QUADRICS_H

#include "tgt/config.h"
#include "tgt/tgt_gl.h"

#include "tgt/renderable.h"
#include "tgt/bounds.h"
#include "tgt/vector.h"
#include "tgt/light.h"
#include "tgt/material.h"


namespace tgt {

/*
    \todo Bounds!
*/

/**
	This class is a wrapper for GLU quadrics. It is
	meant to be a superclass for tgt quadrics and should not
	be instantiated. \n
	All tgt quadrics are inherited from this class and must
	implement the virtual render() method.
	\note { The overridden render() method should call Quadric's render()
			method at the beginning! }
	\note { Bounds are not implemented yet! }
*/
class Quadric : public Renderable {
public:

	/// This struct is used to specifie which kind of
	/// normals are generated.
    enum NormalStyle {
        NONE    = GLU_NONE,		/*!< No normals */
        FLAT    = GLU_FLAT,		/*!< One normal is generated for every facet of a quadric */
        SMOOTH  = GLU_SMOOTH	/*!< One normal is generated for every vertex of a quadric.
									 This is the default value.*/
    };

	/// This struct is used to specifie the direction of the normals. ///
    enum Orientation {
        OUTSIDE = GLU_OUTSIDE ,	/*!< Draw quadric with normals pointing outward. This is the default value. */
        INSIDE  = GLU_INSIDE	/*!< Draw quadric with normals pointing inward. */
    };

	/// This struct is used to specifie the quadrics draw style.
    enum DrawStyle {
        FILL        = GLU_FILL,			/*!< Quadrics are rendered with polygon primitives.	*/
        LINE        = GLU_LINE,			/*!< Quadrics are rendered as a set of lines.		*/
        SILHOUETTE  = GLU_SILHOUETTE,	/*!< Quadrics are rendered as a set of lines,
										     except that edges separating coplanar faces will not be drawn. */
        POINT       = GLU_POINT			/*!< Quadrics are rendered as a set of points.		*/
    };

protected:

    GLUquadricObj*  quadric_;
	/// The quadric's material.
	Material* material_;
	bool materialEnabled_;

private:

    NormalStyle normalStyle_;		/*!< \see NormalStyle */
    bool        textureEnabled_;	/*!< specifies wether texture coordinates are generated */
    Orientation orientation_;		/*!< \see Orientation */
    DrawStyle   drawStyle_;			/*!< \see DrawStyle */

public:

	/// Constructor.
    Quadric(const Bounds& bounds, bool _static, bool visible)
      : Renderable      (bounds, _static, visible),
        quadric_        (gluNewQuadric()),
        material_       (NULL),
        materialEnabled_(false),
		normalStyle_    (SMOOTH),
        textureEnabled_ (false),
        orientation_    (OUTSIDE),
        drawStyle_      (FILL)
    {}

    virtual ~Quadric() {
        gluDeleteQuadric(quadric_);
    }

	virtual void render(){
		if (Light::isEnabledLighting() && materialEnabled_ && material_ != NULL){
			material_->activate();
		}
	}

	/* Getters and Setters */

    /// Return which kind of normals are generated.
	/// \see NormalStyle
	NormalStyle getNormalStyle() const {
        return normalStyle_;
    }

	/// Set which kind of normals are generated.
    /// \see NormalStyle
	void setNormalStyle(NormalStyle normalStyle) {
        gluQuadricNormals(quadric_, normalStyle);
        normalStyle_ = normalStyle;
    }

	/// Return whether quadric is to be textured.
    bool getTextureEnabled() const {
        return textureEnabled_;
    }

	/// Specifie whether quadric is to be textured.
    /// \param true Generate texture coordinates.
	/// \param false Do not generate texture coordinates. This is the default value.
	void setTextureEnabled(bool textureEnabled) {
        gluQuadricTexture(quadric_, textureEnabled);
        textureEnabled_ = textureEnabled;
    }

    /// Get orientation of normals.
	/// \see Orientation
	Orientation getOrientation() const {
        return orientation_;
    }

    /// Set orientation of normals.
	/// \see Orientation
	void setOrientation(Orientation orientation) {
        gluQuadricOrientation(quadric_, orientation);
        orientation_ = orientation;
    }

	/// Return the quadrics draw style.
	/// \see DrawStyle
    DrawStyle getDrawStyle() const {
        return drawStyle_;
    }

	/// Specifie the quadrics draw style.
	/// \see DrawStyle
    void setDrawStyle(DrawStyle drawStyle) {
        gluQuadricDrawStyle  (quadric_, drawStyle);
        drawStyle_ = drawStyle;
    }

    //! apply a material to the quadric
	/// \param enabled enable or disable use of material for rendering
	void setMaterial(Material* material, bool enabled = true){
		material_ = material;
		materialEnabled_ = enabled;
	}

	//! get currently used material
	Material* getMaterial(){
		return material_;
	}

	//! enable or disable use of material for rendering
	/// \note{ acitvation of material is only accepted, if material
	///        has already been set }
	void enableMaterial(bool enable = true){
		if (enable){
			tgtAssert(material_ != NULL, "No material specified!");
			materialEnabled_ = true;
		} else {
			materialEnabled_ = false;
		}
	}

	//! check wether material is activated
	bool isEnabledMaterial(){
		return materialEnabled_;
	}

	virtual void init() {}
    virtual void deinit() {}
};

/**
	Is used to draw a sphere of the given radius centered around the origin.
*/
class Sphere : public Quadric {
protected:

    GLdouble    radius_;		/*!< radius of the sphere */
    GLint       slices_;		/*!< The number of subdivisions around the z-axis (similar to lines of longitude).	*/
    GLint       stacks_;		/*!< The number of subdivisions along the z-axis (similar to lines of latitude).	*/

public:

	/// Constructor.
	/// \param radius radius of the sphere
	/// \param slices The number of subdivisions around the z-axis (similar to lines of longitude).
	/// \param stacks The number of subdivisions along the z-axis (similar to lines of latitude).
	/// \param visible An invisible object is not rendered.
	/// \param _static A static object is not expected to move.
    Sphere( GLdouble radius, GLint slices, GLint stacks,
            bool visible = true, bool _static = true)

      : Quadric(Bounds(vec3(-(float)radius), vec3((float)radius)), _static, visible),
        radius_(radius),
        slices_(slices),
        stacks_(stacks)
    {}

    /// Renders the sphere around the origin.
	void render() {
        if (visible_) {
			Quadric::render();
            gluSphere(quadric_, radius_, slices_, stacks_);
        }
    }

	/// Set radius of the sphere.
	void setRadius(GLdouble radius){
		radius_ = radius;
	}

	/// Get radius of the sphere.
	GLdouble getRadius(){
		return radius_;
	}

	/// Set number of slices.
	/// \see slices_
	void setSlices(GLint slices){
		slices_ = slices;
	}

	/// Get number of slices.
	/// \see slices_
	GLint getSlices(){
		return slices_;
	}


	/// Set number of stacks.
	/// \see stacks_
	void setStacks(GLint stacks){
		stacks_ = stacks;
	}

	/// Get number of stacks.
	/// \see stacks_
	GLint getStacks(){
		return stacks_;
	}

};

/**
	A (two-dimensional) disk on the z = 0 plane
*/
class Disk : public Quadric {
protected:

    GLdouble    innerRadius_;	/*!< The inner radius of the disk (may be zero). If innerRadius > 0
								     the disk has a hole of innerRadius in the middle.	*/
    GLdouble    outerRadius_;	/*!< The outer radius of the disk.						*/
	GLint       slices_;		/*!< The number of subdivisions around the z-axis.		*/
    GLint       loops_;			/*!< The number of concentric rings about the origin
								     into which the disk is subdivided.					*/

public:

	/// Constructor.
	/// \param innerRadius \see innerRadius_
	/// \param outerRadius \see outerRadius_
	/// \param slices \see slices_
	/// \param loops \see loops_
	/// \param visible An invisible object is not rendered.
	/// \param _static A static object is not expected to move.
    Disk(   GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops,
            bool visible = true, bool _static = true)

      : Quadric(Bounds(vec3(), vec3()), _static, visible),
        innerRadius_(innerRadius),
        outerRadius_(outerRadius),
        slices_(slices),
        loops_ (loops)
    {}

	/// Renders the disk on the z = 0 plane, centered at the origin.
    virtual void render() {
        if (visible_) {
			Quadric::render();
            gluDisk(quadric_, innerRadius_, outerRadius_, slices_, loops_);
        }
    }

	///
	/// \see innerRadius_
	void setInnerRadius(GLdouble innerRadius){
		innerRadius_ = innerRadius;
	}

	/// \see innerRadius_
	GLdouble getInnerRadius(){
		return innerRadius_;
	}

	///
	/// \see outerRadius_
	void setOuterRadius(GLdouble outerRadius){
		outerRadius_ = outerRadius;
	}

	///
	/// \see outerRadius_
	GLdouble getOuterRadius(){
		return outerRadius_;
	}

	///
	/// \see slices_
	void setSlices(GLint slices){
		slices_ = slices;
	}

	///
	/// \see slices_
	GLint getSlices(){
		return slices_;
	}

	///
	/// \see loops_
	void setLoops(GLint loops){
		loops_ = loops;
	}

	///
	/// \see loops_
	GLint getLoops(){
		return loops_;
	}

};

/**
	A cylinder oriented along the z-axis. \n
	The base of the cylinder is placed at z = 0, and the top at z = height.
	By setting base or top radius to zero you get a cone.
	The cylinder is open: it has no bottom and top faces.
*/
class Cylinder : public Quadric {
protected:

    GLdouble    baseRadius_;	/*!< The radius of the cylinder at z = 0.			*/
    GLdouble    topRadius_;		/*!< The radius of the cylinder at z = height_.		*/
    GLdouble    height_;		/*!< The height of the cylinder.					*/
    GLint       slices_;		/*!< The number of subdivisions around the z-axis.	*/
    GLint       stacks_;        /*!< The number of subdivisions along the z-axis.	*/

public:

    /// Constructor.
	/// \param baseRadius \see baseRadius_
	/// \param topRadius \see topRadius_
	/// \param height \see height_
	/// \param slices \see slices_
	/// \param stacks \see stacks_
	/// \param visible An invisible object is not rendered.
	/// \param _static A static object is not expected to move.
  	Cylinder(   GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks,
                bool visible = true, bool _static = true)

      : Quadric(Bounds(vec3(), vec3()), _static, visible),
        baseRadius_(baseRadius),
         topRadius_( topRadius),
        height_(height),
        slices_(slices),
        stacks_(stacks)
    {}

	/// Renders the cylinder along the z-axis.
	/// The base of the cylinder is placed at z = 0, and the top at z = height.
    virtual void render() {
        if (visible_) {
			Quadric::render();
            gluCylinder(quadric_, baseRadius_, topRadius_, height_, slices_, stacks_);
        }
    }

	///
	/// \see baseRadius_
	void setBaseRadius(GLdouble baseRadius){
		baseRadius_ = baseRadius;
	}

	///
	/// \see baseRadius_
	GLdouble getBaseRadius(){
		return baseRadius_;
	}

	///
	/// \see topRadius_
	void setTopRadius(GLdouble topRadius){
		topRadius_ = topRadius;
	}

	///
	/// \see topRadius_
	GLdouble getTopRadius(){
		return topRadius_;
	}

	///
	/// \see height_
	void setHeight(GLdouble height){
		height_ = height;
	}

	///
	/// \see height_
	GLdouble getHeight(){
		return height_;
	}

	///
	/// \see slices_
	void setSlices(GLint slices){
		slices_ = slices;
	}

	///
	/// \see slices_
	GLint getSlices(){
		return slices_;
	}

	///
	/// \see stacks_
	void setStacks(GLint stacks){
		stacks_ = stacks;
	}

	///
	/// \see stacks_
	GLint getStacks(){
		return stacks_;
	}
};

/**
	This is the solid version of Cylinder: it is rendered with bottom and top faces.
	The base of the cylinder is placed at z = 0, and the top at z = height.
	By setting base or top radius to zero you get a solid cone.
*/
class SolidCylinder : public Cylinder {
protected:

	Disk bottom_;
	Disk top_;

public:

	/// Constructor.
	/// \param baseRadius The radius of the cylinder at z = 0.
	/// \param topRadius The radius of the cylinder at z = height.
	/// \param height Height of the cylinder.
	/// \param slices The number of subdivisions around the z-axis. Applies to the cylinder and the
	///					bottom and top faces.
	/// \param stacks The number of subdivisions of the cylinder along the z-axis.
	/// \param loops The number of concentric rings about the origin into which the bottom and top disks are subdivided.
	/// \param visible An invisible object is not rendered.
	/// \param _static A static object is not expected to move.
    SolidCylinder(   GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks,
				GLint loops, bool visible = true, bool _static = true)

		: Cylinder(baseRadius, topRadius, height, slices, stacks, _static, visible),
		  bottom_(0, baseRadius, slices, loops, _static, visible),
		  top_(0, topRadius, slices, loops, _static, visible)
	{
		bottom_.setOrientation(Quadric::INSIDE);
	}

	/// Renders the cylinder along the z-axis.
	/// The base of the cylinder is placed at z = 0, and the top at z = height.
	virtual void render(){
		if (visible_){
			Quadric::render();
			Cylinder::render();
			if (baseRadius_ > 0){
				bottom_.render();
			}
			if (topRadius_ > 0){
				glMatrixMode(GL_MODELVIEW);
				glPushMatrix();
				glTranslated(0,0,height_);
				top_.render();
				glPopMatrix();
			}
		}
	}

	void setBaseRadius(GLdouble baseRadius){
		baseRadius_ = baseRadius;
		bottom_.setOuterRadius(baseRadius);
	}

	void setTopRadius(GLdouble topRadius){
		topRadius_ = topRadius;
		top_.setOuterRadius(topRadius);
	}

	void setSlices(GLint slices){
		slices_ = slices;
		bottom_.setSlices(slices);
		top_.setSlices(slices);
	}

	void setLoops(GLint loops){
		bottom_.setLoops(loops);
		top_.setLoops(loops);
	}

	GLint getLoops(){
		return bottom_.getLoops();
	}

	void setStatic(bool _static){
		Cylinder::setStatic(_static);
		bottom_.setStatic(_static);
		top_.setStatic(_static);
	}

	void setNormalStyle(NormalStyle normalStyle) {
		Cylinder::setNormalStyle(normalStyle);
		bottom_.setNormalStyle(normalStyle);
		top_.setNormalStyle(normalStyle);
	}

	void setTextureEnabled(bool _enabled){
		Cylinder::setTextureEnabled(_enabled);
		bottom_.setTextureEnabled(_enabled);
		top_.setTextureEnabled(_enabled);
	}

	void setOrientation(Orientation orientation){
		Cylinder::setOrientation(orientation);
		if (orientation == OUTSIDE)
			bottom_.setOrientation(INSIDE);
		else
			bottom_.setOrientation(OUTSIDE);
		top_.setOrientation(orientation);
	}

	void setDrawStyle(DrawStyle drawStyle){
		Cylinder::setDrawStyle(drawStyle);
		bottom_.setDrawStyle(drawStyle);
		top_.setDrawStyle(drawStyle);
	}
};


/**
	A rectangle oriented at x-y-plane. \n
	The center of the rectangle is placed at x = 0, y = 0, z = 0.
*/
class Rect : public Quadric {
protected:

    GLdouble    width_;
    GLdouble    height_;

    GLdouble    h_width_;
    GLdouble    h_height_;

public:

	/// Constructor.
	/// \param width The width of the rectangle.
	/// \param height The height of the rectangle.
	/// \param visible An invisible object is not rendered.
	/// \param _static A static object is not expected to move.
    Rect(   GLdouble width, GLdouble height,
		bool visible = true, bool _static = true)
      : Quadric(Bounds(vec3(), vec3()), _static, visible)
	{
		setWidth(width);
		setHeight(height);
	}

	/// Renders the rectangle in the x-y-plane.
	/// The center of the rectangle is in (0,0,0)
	/// e.g. the measures in x direction: -(width / 2.0), (width / 2.0)
	virtual void render(){
		if (visible_) {

			Quadric::render();

			switch (getDrawStyle()) {
			case LINE:
				glBegin(GL_LINE_STRIP);
				break;
			case SILHOUETTE:
				glBegin(GL_LINE_STRIP);
				break;
			case POINT:
				glBegin(GL_POINTS);
				break;
			default:
				glBegin(GL_QUADS);
				break;
			}


			// if FLAT or SMOOTH set normals
			if (getNormalStyle() != NONE) {
				//set normal (inside or outside)
				if (getOrientation() == INSIDE) {
					glNormal3f(0,0,-1);
				} else {
					glNormal3f(0,0, 1);
				}
			}

			// render the rectangle
			glVertex3d(-h_width_, -h_height_, 0);
			glVertex3d(-h_width_,  h_height_, 0);
			glVertex3d( h_width_,  h_height_, 0);
			glVertex3d( h_width_, -h_height_, 0);

			if ((getDrawStyle() == LINE) || (getDrawStyle() == SILHOUETTE)) {
				glVertex3d(-h_width_, -h_height_, 0);
			}

			glEnd();
		}
	}

	/// Returns the width of the rectangle
	GLdouble getWidth() {
		return width_;
	}

	/// Sets the width of the rectangle
	void setWidth(GLdouble w) {
		width_ = w;
		h_width_ = w / 2.0;
	}

	/// Returns the height of the rectangle
	GLdouble getHeight() {
		return height_;
	}

	/// Sets the height of the rectangle
	void setHeight(GLdouble h) {
		height_ = h;
		h_height_ = h / 2.0;
	}
};

/**
	A quad centered around the origin. \n
	It is created of six rectangle objects.
*/
class Quad : public Quadric {
protected:

    GLdouble    width_;
    GLdouble    height_;
    GLdouble    depth_;

private:

	GLdouble	h_width_;
	GLdouble	h_height_;
	GLdouble	h_depth_;

	Rect* front_;
	Rect* back_;
	Rect* top_;
	Rect* bottom_;
	Rect* right_;
	Rect* left_;

	void initializeRects() {
            front_  = new Rect(width_, height_, true);
            back_   = new Rect(width_, height_, true);
            top_    = new Rect(width_, depth_, true);
            bottom_ = new Rect(width_, depth_, true);
            right_  = new Rect(height_, depth_, true);
            left_   = new Rect(height_, depth_, true);
	}

	void deleteRects() {
            delete front_;
            delete back_;
            delete top_;
            delete bottom_;
            delete right_;
            delete left_;
	}

public:

	/// Constructor.
	/// \param width The width of the rectangle.
	/// \param height The height of the rectangle.
	/// \param depth The depth of the rectangle.
	/// \param visible An invisible object is not rendered.
	/// \param _static A static object is not expected to move.
	Quad(   GLdouble width, GLdouble height, GLdouble depth,
		bool visible = true, bool _static = true)
      : Quadric(Bounds(vec3(), vec3()), _static, visible)
	{
            initializeRects();
            
            setWidth(width);
            setHeight(height);
            setDepth(depth);
	}

        /// Destructor
        ~Quad() {
            deleteRects();
        }

	/// Renders the quad.
	/// The center of the quad is in (0,0,0)
	/// eg. the measures in x direction: -(width / 2.0), (width / 2.0)
	virtual void render(){
		if (visible_) {

			Quadric::render();

			glPushMatrix();
				glTranslated(0,0,h_depth_);
				front_->render();
			glPopMatrix();

			glPushMatrix();
				glTranslated(0,0,-h_depth_);
				glRotatef(180.f, 1.f, 0.f, 0.f);
				back_->render();
			glPopMatrix();

			glPushMatrix();
				glTranslated(0,h_height_,0);
				glRotatef(90.f, -1.f, 0.f, 0.f);
				top_->render();
			glPopMatrix();

			glPushMatrix();
				glTranslated(0,-h_height_,0);
				glRotatef(90.f, 1.f, 0.f, 0.f);
				bottom_->render();
			glPopMatrix();

			glPushMatrix();
				glTranslated(h_width_,0,0);
				glRotatef(90.f, 0.f, 1.f, 0.f);
                glRotatef(90.f, 0.f, 0.f, 1.f);
				right_->render();
			glPopMatrix();

			glPushMatrix();
				glTranslated(-h_width_,0,0);
				glRotatef(90, 0.f,-1.f, 0.f);
                glRotatef(90, 0.f,0.f, 1.f);
				left_->render();
			glPopMatrix();
		}
    }

	/// Returns the width of the quad
	GLdouble getWidth() {
		return width_;
	}

	/// Sets the width of the quad
	void setWidth(GLdouble w) {
		width_ = w;
		h_width_ = width_ / 2.0;
                deleteRects();
		initializeRects();
	}

	/// Returns the height of the quad
	GLdouble getHeight() {
		return height_;
	}

	/// Sets the height of the quad
	void setHeight(GLdouble h) {
		height_ = h;
		h_height_ = height_ / 2.0;
                deleteRects();
		initializeRects();
	}

	/// Returns the depth of the quad
	GLdouble getDepth() {
		return depth_;
	}

	/// Sets the depth of the quad
	void setDepth(GLdouble d) {
		depth_ = d;
		h_depth_ = depth_ / 2.0;
                deleteRects();
		initializeRects();
	}

	NormalStyle getNormalStyle() {
		return front_->getNormalStyle();
	}

	void setNormalStyle(NormalStyle normalStyle) {
		front_->setNormalStyle(normalStyle);
		back_->setNormalStyle(normalStyle);
		bottom_->setNormalStyle(normalStyle);
		top_->setNormalStyle(normalStyle);
		right_->setNormalStyle(normalStyle);
		left_->setNormalStyle(normalStyle);
	}

	bool getTextureEnabled() {
		return front_->getTextureEnabled();
	}

	void setTextureEnabled(bool _enabled){
		front_->setTextureEnabled(_enabled);
		back_->setTextureEnabled(_enabled);
		bottom_->setTextureEnabled(_enabled);
		top_->setTextureEnabled(_enabled);
		right_->setTextureEnabled(_enabled);
		left_->setTextureEnabled(_enabled);
	}

	Orientation getOrientation() {
		return front_->getOrientation();
	}

	void setOrientation(Orientation orientation){
		front_->setOrientation(orientation);
		back_->setOrientation(orientation);
		bottom_->setOrientation(orientation);
		top_->setOrientation(orientation);
		right_->setOrientation(orientation);
		left_->setOrientation(orientation);
	}

	DrawStyle getDrawStyle() {
		return front_->getDrawStyle();
	}

	void setDrawStyle(DrawStyle drawStyle){
		front_->setDrawStyle(drawStyle);
		back_->setDrawStyle(drawStyle);
		bottom_->setDrawStyle(drawStyle);
		top_->setDrawStyle(drawStyle);
		right_->setDrawStyle(drawStyle);
		left_->setDrawStyle(drawStyle);
	}
};


/**
	An arc of a disk specified by a start and a sweep angle. \n
	It is rendered on the z=0 plane, centered at the origin.
*/
class PartialDisk : public Disk {
protected:

    GLdouble    startAngle_;	/*!< The starting angle, in degrees, of the disk portion.
								     0 degrees is along the positive y-axis.				*/
    GLdouble    sweepAngle_;	/*!< The sweep angle, in degrees, of the disk portion.
								     Rotation is clockwise around the z-axis.				*/

public:

	/// Constructor.
	/// \param startAngle The starting angle, in degrees, of the disk portion. 0 degrees is along the positive y-axis.
    /// \param sweepAngle The sweep angle, in degrees, of the disk portion. Rotation is clockwise around the z-axis.
	PartialDisk(    GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops,
                    GLdouble startAngle, GLdouble sweepAngle,
                    bool visible = true, bool _static = true)
      : Disk(   innerRadius, outerRadius, slices, loops,
                _static, visible),
        startAngle_(startAngle),
        sweepAngle_(sweepAngle)
    {}

	/// Renders the partial disk on the z=0 plane, centered at the origin.
    virtual void render() {
		if (visible_){
			Quadric::render();
			gluPartialDisk( quadric_, innerRadius_, outerRadius_, slices_, loops_,
				            startAngle_, sweepAngle_);
		}
	}

	///
	/// see \startAngle_
	void setStartAngle(GLdouble startAngle){
		startAngle_ = startAngle;
	}

	///
	/// see \startAngle_
	GLdouble getStartAngle(){
		return startAngle_;
	}

	///
	/// see \sweepAngle_
	void setSweepAngle(GLdouble sweepAngle){
		sweepAngle_ = sweepAngle;
	}

	///
	/// see \sweepAngle_
	GLdouble getSweepAngle(){
		return sweepAngle_;
	}

};

}

#endif //TGT_QUADRICS_H
